#include "shell-screenshot.h"
#include "shell-util.h"
+typedef enum _ShellScreenshotFlag
+{
+ SHELL_SCREENSHOT_FLAG_NONE,
+ SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR,
+} ShellScreenshotFlag;
+
typedef struct _ShellScreenshotPrivate ShellScreenshotPrivate;
struct _ShellScreenshot
cairo_surface_t *image;
cairo_rectangle_int_t screenshot_area;
- gboolean include_cursor;
gboolean include_frame;
};
G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
-static void
-grab_screenshot (ClutterActor *stage,
- GTask *result);
-
static void
shell_screenshot_class_init (ShellScreenshotClass *screenshot_class)
{
g_clear_pointer (&priv->image, cairo_surface_destroy);
g_clear_object (&priv->stream);
g_clear_pointer (&priv->datetime, g_date_time_unref);
-
- meta_enable_unredirect_for_display (shell_global_get_display (priv->global));
}
static void
}
static void
-do_grab_screenshot (ShellScreenshot *screenshot,
- ClutterStage *stage,
- int x,
- int y,
- int width,
- int height)
+do_grab_screenshot (ShellScreenshot *screenshot,
+ int x,
+ int y,
+ int width,
+ int height,
+ ShellScreenshotFlag flags)
{
ShellScreenshotPrivate *priv = screenshot->priv;
+ ClutterStage *stage = shell_global_get_stage (priv->global);
cairo_rectangle_int_t screenshot_rect = { x, y, width, height };
- ClutterCapture *captures;
- int n_captures;
- int i;
-
- if (!clutter_stage_capture (stage, FALSE,
- &screenshot_rect,
- &captures,
- &n_captures))
- return;
-
- if (n_captures == 1)
- priv->image = cairo_surface_reference (captures[0].image);
+ int image_width;
+ int image_height;
+ float scale;
+ cairo_surface_t *image;
+ ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_NONE;
+ g_autoptr (GError) error = NULL;
+
+ clutter_stage_get_capture_final_size (stage, &screenshot_rect,
+ &image_width,
+ &image_height,
+ &scale);
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ image_width, image_height);
+
+ if (flags & SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR)
+ paint_flags |= CLUTTER_PAINT_FLAG_FORCE_CURSORS;
else
+ paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS;
+ if (!clutter_stage_paint_to_buffer (stage, &screenshot_rect, scale,
+ cairo_image_surface_get_data (image),
+ cairo_image_surface_get_stride (image),
+ CLUTTER_CAIRO_FORMAT_ARGB32,
+ paint_flags,
+ &error))
{
- float target_scale;
-
- clutter_stage_get_capture_final_size (stage, &screenshot_rect,
- &width, &height, &target_scale);
- priv->image = shell_util_composite_capture_images (captures,
- n_captures,
- x, y,
- width, height,
- target_scale);
+ cairo_surface_destroy (image);
+ g_warning ("Failed to take screenshot: %s", error->message);
+ return;
}
- priv->datetime = g_date_time_new_now_local ();
-
- for (i = 0; i < n_captures; i++)
- cairo_surface_destroy (captures[i].image);
+ priv->image = image;
- g_free (captures);
-}
-
-static gboolean
-should_draw_cursor_image (ShellScreenshotMode mode)
-{
- if (mode == SHELL_SCREENSHOT_WINDOW || !meta_is_wayland_compositor ())
- {
- StSettings *settings = st_settings_get ();
- gboolean magnifier_active = FALSE;
-
- g_object_get (settings, "magnifier-active", &magnifier_active, NULL);
-
- if (!magnifier_active)
- return TRUE;
- }
-
- return FALSE;
+ priv->datetime = g_date_time_new_now_local ();
}
static void
}
static void
-on_paint (ClutterActor *actor,
- ClutterPaintContext *paint_context,
- GTask *result)
-{
- grab_screenshot (actor, result);
-}
-
-static void
-on_actors_painted (ClutterActor *actor,
- GTask *result)
-{
- grab_screenshot (actor, result);
-}
-
-static void
-grab_screenshot (ClutterActor *stage,
- GTask *result)
+grab_screenshot (ShellScreenshot *screenshot,
+ ShellScreenshotFlag flags,
+ GTask *result)
{
+ ShellScreenshotPrivate *priv = screenshot->priv;
MetaDisplay *display;
int width, height;
- ShellScreenshot *screenshot = g_task_get_source_object (result);
- ShellScreenshotPrivate *priv = screenshot->priv;
GTask *task;
display = shell_global_get_display (priv->global);
meta_display_get_size (display, &width, &height);
- do_grab_screenshot (screenshot, CLUTTER_STAGE (stage), 0, 0, width, height);
-
- if (meta_display_get_n_monitors (display) > 1)
- {
- cairo_region_t *screen_region = cairo_region_create ();
- cairo_region_t *stage_region;
- MetaRectangle monitor_rect;
- cairo_rectangle_int_t stage_rect;
- int i;
- cairo_t *cr;
-
- for (i = meta_display_get_n_monitors (display) - 1; i >= 0; i--)
- {
- meta_display_get_monitor_geometry (display, i, &monitor_rect);
- cairo_region_union_rectangle (screen_region,
- (const cairo_rectangle_int_t *) &monitor_rect);
- }
-
- stage_rect.x = 0;
- stage_rect.y = 0;
- stage_rect.width = width;
- stage_rect.height = height;
-
- stage_region = cairo_region_create_rectangle ((const cairo_rectangle_int_t *) &stage_rect);
- cairo_region_xor (stage_region, screen_region);
- cairo_region_destroy (screen_region);
-
- cr = cairo_create (priv->image);
-
- for (i = 0; i < cairo_region_num_rectangles (stage_region); i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (stage_region, i, &rect);
- cairo_rectangle (cr, (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
- cairo_fill (cr);
- }
-
- cairo_destroy (cr);
- cairo_region_destroy (stage_region);
- }
+ do_grab_screenshot (screenshot,
+ 0, 0, width, height,
+ flags);
priv->screenshot_area.x = 0;
priv->screenshot_area.y = 0;
priv->screenshot_area.width = width;
priv->screenshot_area.height = height;
- if (priv->include_cursor)
- draw_cursor_image (priv->image, priv->screenshot_area);
-
- g_signal_handlers_disconnect_by_func (stage, on_paint, result);
- g_signal_handlers_disconnect_by_func (stage, on_actors_painted, result);
-
task = g_task_new (screenshot, NULL, on_screenshot_written, result);
g_task_run_in_thread (task, write_screenshot_thread);
g_object_unref (task);
}
static void
-grab_area_screenshot (ClutterActor *stage,
- GTask *result)
+grab_window_screenshot (ShellScreenshot *screenshot,
+ ShellScreenshotFlag flags,
+ GTask *result)
{
- ShellScreenshot *screenshot = g_task_get_source_object (result);
- ShellScreenshotPrivate *priv = screenshot->priv;
- GTask *task;
-
- do_grab_screenshot (screenshot,
- CLUTTER_STAGE (stage),
- priv->screenshot_area.x,
- priv->screenshot_area.y,
- priv->screenshot_area.width,
- priv->screenshot_area.height);
-
- g_signal_handlers_disconnect_by_func (stage, grab_area_screenshot, result);
- task = g_task_new (screenshot, NULL, on_screenshot_written, result);
- g_task_run_in_thread (task, write_screenshot_thread);
- g_object_unref (task);
-}
-
-static void
-grab_window_screenshot (ClutterActor *stage,
- GTask *result)
-{
- ShellScreenshot *screenshot = g_task_get_source_object (result);
ShellScreenshotPrivate *priv = screenshot->priv;
GTask *task;
MetaDisplay *display = shell_global_get_display (priv->global);
NULL);
priv->datetime = g_date_time_new_now_local ();
- if (priv->include_cursor)
+ if (flags & SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR)
{
if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
draw_cursor_image (priv->image, priv->screenshot_area);
}
- g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result);
task = g_task_new (screenshot, NULL, on_screenshot_written, result);
g_task_run_in_thread (task, write_screenshot_thread);
g_object_unref (task);
}
-static void
-grab_pixel (ClutterActor *stage,
- GTask *result)
-{
- ShellScreenshot *screenshot = g_task_get_source_object (result);
- ShellScreenshotPrivate *priv = screenshot->priv;
-
- do_grab_screenshot (screenshot,
- CLUTTER_STAGE (stage),
- priv->screenshot_area.x,
- priv->screenshot_area.y,
- 1,
- 1);
-
- meta_enable_unredirect_for_display (shell_global_get_display (priv->global));
-
- g_signal_handlers_disconnect_by_func (stage, grab_pixel, result);
- g_task_return_boolean (result, TRUE);
- g_object_unref (result);
-}
-
static gboolean
finish_screenshot (ShellScreenshot *screenshot,
GAsyncResult *result,
GAsyncReadyCallback callback,
gpointer user_data)
{
- ClutterActor *stage;
ShellScreenshotPrivate *priv;
- gboolean use_paint_signal = FALSE;
GTask *result;
+ ShellScreenshotFlag flags;
g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot));
g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
g_task_set_source_tag (result, shell_screenshot_screenshot);
priv->stream = g_object_ref (stream);
- priv->include_cursor = FALSE;
-
- stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
-
- meta_disable_unredirect_for_display (shell_global_get_display (priv->global));
+ flags = SHELL_SCREENSHOT_FLAG_NONE;
if (include_cursor)
- {
- if (should_draw_cursor_image (SHELL_SCREENSHOT_SCREEN))
- priv->include_cursor = TRUE;
- else
- use_paint_signal = TRUE;
- }
+ flags |= SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR;
- if (use_paint_signal)
- {
- g_signal_connect_after (stage, "paint",
- G_CALLBACK (on_paint),
- result);
- }
- else
- {
- g_signal_connect_after (stage, "actors-painted",
- G_CALLBACK (on_actors_painted),
- result);
- }
-
- clutter_actor_queue_redraw (stage);
+ grab_screenshot (screenshot, flags, result);
}
/**
GAsyncReadyCallback callback,
gpointer user_data)
{
- ClutterActor *stage;
ShellScreenshotPrivate *priv;
GTask *result;
+ g_autoptr (GTask) task = NULL;
g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot));
g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
priv->screenshot_area.width = width;
priv->screenshot_area.height = height;
- stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
-
- meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
-
- g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_area_screenshot), result);
+ do_grab_screenshot (screenshot,
+ priv->screenshot_area.x,
+ priv->screenshot_area.y,
+ priv->screenshot_area.width,
+ priv->screenshot_area.height,
+ SHELL_SCREENSHOT_FLAG_NONE);
- clutter_actor_queue_redraw (stage);
+ task = g_task_new (screenshot, NULL, on_screenshot_written, result);
+ g_task_run_in_thread (task, write_screenshot_thread);
}
/**
{
ShellScreenshotPrivate *priv;
MetaDisplay *display;
- ClutterActor *stage;
MetaWindow *window;
GTask *result;
priv->stream = g_object_ref (stream);
priv->include_frame = include_frame;
- priv->include_cursor = include_cursor &&
- should_draw_cursor_image (SHELL_SCREENSHOT_WINDOW);
-
- stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
- meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
-
- g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_window_screenshot), result);
-
- clutter_actor_queue_redraw (stage);
+ grab_window_screenshot (screenshot, include_cursor, result);
}
/**
gpointer user_data)
{
ShellScreenshotPrivate *priv;
- MetaDisplay *display;
- ClutterActor *stage;
- GTask *result;
+ g_autoptr (GTask) result = NULL;
g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot));
priv->screenshot_area.width = 1;
priv->screenshot_area.height = 1;
- display = shell_global_get_display (priv->global);
- stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
-
- meta_disable_unredirect_for_display (display);
-
- g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_pixel), result);
+ do_grab_screenshot (screenshot,
+ priv->screenshot_area.x,
+ priv->screenshot_area.y,
+ 1,
+ 1,
+ SHELL_SCREENSHOT_FLAG_NONE);
- clutter_actor_queue_redraw (stage);
+ g_task_return_boolean (result, TRUE);
}
#if G_BYTE_ORDER == G_LITTLE_ENDIAN